home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Special 18
/
AMIGAplus Sonderheft 18 (1999)(ICP)(DE)[!].iso
/
PD
/
Spiele
/
InvasionForce
/
Source
/
cyber1.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-08
|
19KB
|
619 lines
/*
AI Code for Invasion Force - an Explore/Conquer Strategic Wargame
Copyright (C) 1996 Brannen Hough
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
cyber1.c -- artificial intelligence module for Empire II
*/
/* This file contains all the routines associated with AI Type #1.
*/
#include "global.h"
/***************************************************************
*************** Production Routines ***************************
***************************************************************/
struct GovNode* AI1_locate_gov( struct City* metro )
{
struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
struct GovNode *NewGov = NULL;
for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ) {
if ((Gov->owner == player) &&
((Gov->type == GOV_CITY) || (Gov->type == GOV_PORT))
&& (Gov->x == metro->col) && (Gov->y == metro->row)) {
/* We found the right city governor. */
return( Gov );
} /* End if */
} /* End for loop */
/* Never found it */
NewGov = AI1_add_gov( metro );
/* And, let's set up the governors area of interest */
AI1_setup_area_of_interest (NewGov);
return (NewGov);
}
struct GovNode* AI1_add_gov( struct City* metro )
{
struct GovNode *new_gov = AllocVec((int)sizeof(*new_gov),MEMF_CLEAR);
new_gov->x = metro->col;
new_gov->y = metro->row;
new_gov->targx = -1;
new_gov->targy = -1;
new_gov->searchx = -1;
new_gov->searchy = -1;
new_gov->mode = GOV_SEARCH;
new_gov->flags = 0;
new_gov->owner = player;
if (port_cityP(metro)) new_gov->type = GOV_PORT;
else new_gov->type = GOV_CITY;
new_gov->ID = NewGov++;
sprintf (outbuf, "Creating Governor %ld at %ld,%ld",
new_gov->ID, new_gov->x, new_gov->y);
DEBUG_AI(outbuf)
/* Add the new governor to the list of governors */
AddTail((struct List *)&GovList,(struct Node *)new_gov);
return( new_gov );
}
void AI1_set_gov_prod (struct City *metro, struct GovNode *CityOwner)
{
CityOwner->req.type = RIFLE;
CityOwner->req.req_gov = CityOwner->ID;
CityOwner->req.priority = 9;
/* And we set the city itself to produce this */
if (metro->unit_type != CityOwner->req.type) { /*making a new type */
metro->unit_type = CityOwner->req.type;
/* Tooling up penalty */
metro->unit_wip = -1 * wishbook[metro->unit_type].build/5;
/*sprintf (outbuf, "Tooling Up the city to build a %s",
UnitString[metro->unit_type]);
DEBUG_AI(outbuf) */
}
/* unit->wip has been set to zero elsewhere. Don't zero out production
that has already been started when we haven't changed the type.
We have enough handicaps as it is. */
return;
}
void AI1_play_turn ( int new_units )
{
int MaxLooping = 1000;
/* Here we may want to look around, give out some orders to units,
and execute orders to units in a loop until we have done all the
moves possible for the units.
*/
AI1_do_all_histograms();
AI1_give_orders();
/* We'll add a little failsafe so we don't spend eternity here */
while( (MaxLooping > 0) && (!AI1_do_unit_actions()) ) MaxLooping--;
if( MaxLooping <= 0 )
DEBUG_AI("Exitting AI player's turn - out of actions")
return;
}
void AI1_setup_area_of_interest( struct GovNode* Gov )
{
/* Set up the immediate area of interest */
Gov->startx = Gov->x - GOVERNOR_RADIUS;
Gov->starty = Gov->y - GOVERNOR_RADIUS;
Gov->endx = Gov->x + GOVERNOR_RADIUS;
Gov->endy = Gov->y + GOVERNOR_RADIUS;
if (!wrap) {
if (Gov->startx < 0) Gov->startx = 0;
if (Gov->starty < 0) Gov->starty = 0;
if (Gov->endx > width - 1) Gov->endx = width - 1;
if (Gov->endy > height - 1) Gov->endy = height - 1;
}
else {
if (Gov->startx < 0) Gov->startx += width;
if (Gov->starty < 0) Gov->starty += height;
if (Gov->endx > width - 1) Gov->endx -= width;
if (Gov->endy > height - 1) Gov->endy -= height;
}
/* Set up the Extended area of interest */
Gov->Estartx = Gov->x - EXTENDED_RADIUS;
Gov->Estarty = Gov->y - EXTENDED_RADIUS;
Gov->Eendx = Gov->x + EXTENDED_RADIUS;
Gov->Eendy = Gov->y + EXTENDED_RADIUS;
if (!wrap) {
if (Gov->Estartx < 0) Gov->Estartx = 0;
if (Gov->Estarty < 0) Gov->Estarty = 0;
if (Gov->Eendx > width - 1) Gov->Eendx = width - 1;
if (Gov->Eendy > height - 1) Gov->Eendy = height - 1;
}
else {
if (Gov->Estartx < 0) Gov->Estartx += width;
if (Gov->Estarty < 0) Gov->Estarty += height;
if (Gov->Eendx > width - 1) Gov->Eendx -= width;
if (Gov->Eendy > height - 1) Gov->Eendy -= height;
}
/* sprintf (outbuf,
"For Gov %ld, Startx:%ld, Starty:%ld, Endx:%ld, Endy:%ld",
Gov->ID, Gov->startx, Gov->starty, Gov->endx, Gov->endy);
DEBUG_AI(outbuf)
*/
return;
}
void AI1_do_all_histograms()
{
struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
/* First we update the picture for all the Governors */
for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ)
if (Gov->owner == player) {
AI1_do_one_histogram (Gov);
AI1_set_gov_mode (Gov);
}
/* End for loop */
}
void AI1_do_one_histogram( struct GovNode* Gov)
{
int j, k;
struct MapIcon *icon = (struct MapIcon *)PLAYER.icons.mlh_Head;
struct Unit *unit = (struct Unit *)unit_list.mlh_Head;
/* Zero out the histogram for the governor */
for (j = 0; j < 16; j++) {
Gov->hist.TerrainCounts[j] = 0;
Gov->hist.UnitCounts[j] = 0;
Gov->hist.EnemyCounts[j] = 0;
}
Gov->hist.TotalEUnits = 0;
Gov->hist.TotalMyUnits = 0;
Gov->hist.TotalCities = 0;
Gov->hist.TotalMyCities = 0;
for (j = Gov->startx; j <= Gov->endx ; j++) {
for (k = Gov->starty; k <= Gov->endy; k++) {
Gov->hist.TerrainCounts[get(PLAYER.map,j,k)]++;
} /* End for k */
} /* End for j */
SetNeutralCity (Gov);
for (; icon->inode.mln_Succ; icon = (struct MapIcon *)
icon->inode.mln_Succ) {
if ((icon->owner != player) && (icon->col >= Gov->Estartx)
&& (icon->col <= Gov->Eendx) && (icon->row >= Gov->Estarty)
&& (icon->row <= Gov->Eendy)) {
Gov->hist.EnemyCounts[icon->type]++;
if( (AI5_GetDist( Gov->x, Gov->y, icon->col, icon->row ) <= 6)
&& ( (icon->type == ARMOR) || (icon->type == RIFLE) ||
(icon->type == AIRCAV) || (icon->type == TRANSPORT) ||
(icon->type == BOMBER) ) )
SetCityThreatened(Gov);
if (icon->type != CITY) Gov->hist.TotalEUnits++;
/*sprintf (outbuf, "City %ld found enemy %s at %ld,%ld",
Gov->ID, UnitString[icon->type],icon->col, icon->row);
DEBUG_AI(outbuf)
*/
if ((icon->owner != 0) && (icon->type == CITY))
ClearNeutralCity (Gov);
} /* End if enemy unit detected in our area */
} /* End for loop for icons */
for (; unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ) {
if ((unit->owner == player) &&
(Gov->ID == atoi(unit->name))) {
Gov->hist.UnitCounts[unit->type]++;
Gov->hist.TotalMyUnits++;
} /* End if we own it and it is owned by this governor */
} /* End for looking at friendly units */
}
void AI1_set_gov_mode( struct GovNode* Gov )
{
if ((Gov->type == GOV_CITY) || (Gov->type == GOV_PORT)) {
/* Check to see if we still own our city */
if (hex_owner(Gov->x, Gov->y) == player) ClearCityTaken(Gov);
else {
SetCityTaken(Gov);
// clear all orders
AI1_clear_all_orders(Gov);
}
}
return;
}
void AI1_clear_all_orders( struct GovNode* Gov )
{
struct Unit* unit = (struct Unit*) unit_list.mlh_Head;
// Mode has changed - clear all orders for all units owned by gov
for (; unit->unode.mln_Succ; unit = (struct Unit *)
unit->unode.mln_Succ)
if ((unit->owner == player) && (atoi(unit->name)
== Gov->ID)) clear_orders(unit);
// End if all that stuff
// End for loop
return;
}
void AI1_give_orders()
{
struct Unit *unit = (struct Unit *)unit_list.mlh_Head;
struct GovNode *Gov = NULL;
for (;unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ)
if ((unit->owner == player) && (unit->move > 0) &&
(unit->orders == NULL)) {
/* No orders yet, let's set some
Ok, we own the unit, and it has moves left, and has a Governor
owner, and has no standing orders
Don't just stand there, do something!
*/
/* sprintf(outbuf, "Giving initial orders to unit named %s at %ld,%ld",
unit->name, unit->col, unit->row);
DEBUG_AI(outbuf)
*/
Gov = AI1_FindOwner (unit);
if (Gov != NULL) {
if( IsCityTaken( Gov ) ) {
/* Have the unit move to the city's location */
ComputerGiveOrders (unit, C_ORDER_GOTO, Gov->x,
Gov->y, -1, -1, -1);
}
else {
/* Have the unit wander randomly */
ComputerGiveOrders (unit, C_ORDER_RANDOM, -1, -1,
-1,-1, -1);
}
}
} /* end if owner and has moves left */
/* End For */
}
struct GovNode* AI1_FindOwner (struct Unit *unit)
{
int owner;
struct GovNode *Gov = (struct GovNode *)GovList.mlh_Head;
if (unit->name == NULL) {
DEBUG_AI("Unit name is NULL")
return (NULL);
}
owner = atoi(unit->name);
for ( ; Gov->gnode.mln_Succ; Gov = (struct GovNode *)Gov->gnode.mln_Succ)
/* We have two checks and three fail safes here.
We must make sure we don't cheat and that the names are
not NULL (strcmp is not defined in that case)
*/
if ((Gov->owner == unit->owner) && (Gov->owner == player)
&& (Gov->ID == owner))
return (Gov);
/* End For, If */
sprintf (outbuf,"Unable to find owning Governor for unit %s", unit->name);
DEBUG_AI(outbuf)
return (NULL);
}
void AI1_computer_give_orders(struct Unit *unit,int suborder,short destx,
short desty,short orgx,short orgy,int etc)
{
struct Order *order=AllocVec((long)sizeof(*order),MEMF_CLEAR);
clear_orders(unit);
if (order) {
order->destx = destx;
order->desty = desty;
unit->orders = order;
order->type = ORDER_NONE;
if (orgx == -1) order->orgx = unit->col;
else order->orgx = orgx;
if (orgy == -1) order->orgy = unit->row;
else order->orgy = orgy;
order->processed = FALSE;
order->etc = etc;
order->reserved = suborder; /* using reserved for computer
orders so I don't tread on the human
player's tokens. */
/* This is set up to be in the order they are used most often,
and set up so that more order types can be added as needed.
*/
switch (suborder) {
case C_ORDER_GOTO:
/* sprintf (outbuf, "%s %s C_ORDER_GOTO from %ld,%ld to %ld,%ld",
UnitString[unit->type], unit->name, order->orgx,
order->orgy, order->destx, order->desty);
DEBUG_AI(outbuf)
*/
break;
case C_ORDER_RANDOM:
/* Standard stuff only */
break;
}
}
}
int AI1_do_unit_actions()
{
struct Unit *unit = (struct Unit *)unit_list.mlh_Head;
struct GovNode *Gov = NULL;
int Done = TRUE;
for ( ; unit->unode.mln_Succ; unit = (struct Unit *) unit->unode.mln_Succ)
if ((unit->owner==player) && (unit->move > 0)) {
/* Skip Sentry units */
if ((unit->orders == NULL) ||
(unit->orders->reserved != C_ORDER_SENTRY)) Done = FALSE;
/* Take a look around us and react to enemy units + cities */
if( AI1_look_around ( unit ) ) return (FALSE);
/* if we have orders, execute them */
if (unit->orders != NULL) {
AI1_execute_standing_order(unit);
return (Done);
}
else {
Gov = AI1_FindOwner (unit);
if (Gov != NULL) {
DEBUG_AI("No orders, no enemy around. Huh?")
unit->move = 0;
return (Done);
} /* End if Gov != NULL */
else {
DEBUG_AI("Cannot find unit owner to ad lib turn")
DEBUG_AI("For Now, Forget IT!")
sprintf (outbuf, "%s Unit %s at %ld,%ld",
UnitString[unit->type], unit->name, unit->col,
unit->row);
DEBUG_AI(outbuf)
unit->move = 0;
return (Done);
} /* End else Gov == NULL */
} /* End else figure something out */
} /* End if we own unit and it has moves left */
/* End for loop */
return (Done);
}
int AI1_look_around( struct Unit* unit)
{
int i, k;
short targx, targy;
struct City* metro;
for (i = 0; i < 6; i++) {
if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
if ((metro = city_hereP (targx, targy)) &&
(metro->owner != player)) {
/* if there is a city here and we don't own it */
if ((unit->type == RIFLE) || (unit->type == ARMOR)
|| (unit->type == AIRCAV)) {
/* Go for it! */
/* DEBUG_AI("Jumping enemy city") */
(void) move_unit_xy (unit, targx, targy);
return (1);
} /* End if can take city */
} /* End if city here and it ain't ours! */
} /* End if hex here */
} /* End For loop */
for (i = 0; i < 6; i++) {
if (AI1_calc_dir (i, unit->col, unit->row, &targx, &targy) != -1) {
if (((k = hex_owner(targx,targy)) > 0)&&(k!=player)) {
/* Somebody there - for now just jump 'em */
/*DEBUG_AI("Jumping enemy unit") */
(void) move_unit_xy (unit, targx, targy);
return (1);
} /* End if bad guy here */
} /* End if hex here */
} /* End for loop */
return (0);
}
/* This routine calculates the new coordinates resulting from heading in
a particular direction from given coordinates. Returns -1 for not
possible, and a 1 for OK.
*/
int AI1_calc_dir (enum Direction dir, short orgx, short orgy,
short *x, short *y)
{
int targx = orgx;
int targy = orgy;
switch (dir) {
case EAST:
targx++;
break;
case WEST:
targx--;
break;
case NORTHEAST:
targy--;
if (orgy%2) /* odd number */
targx++;
break;
case NORTHWEST:
targy--;
if (!(orgy%2)) /* even number */
targx--;
break;
case SOUTHEAST:
targy++;
if (orgy%2) /* odd number */
targx++;
break;
case SOUTHWEST:
targy++;
if (!(orgy%2)) /* even number */
targx--;
break;
default:
return (-1);
}
/* correct values for wrap, if it's active */
if (wrap) {
if (targx<0)
targx += width;
if (targx>=width)
targx -= width;
if (targy<0)
targy += height;
if (targy>=height)
targy -= height;
}
/* he certainly can't move off the map! */
if (targx<0 || targx>=width || targy<0 || targy>=height) {
DEBUG_AI("Moving Off Map")
return(-1);
}
*x = targx;
*y = targy;
return (1);
}
void AI1_execute_standing_order( struct Unit* unit)
{
int result;
if ((unit->orders == NULL) || (unit->orders->type != ORDER_NONE)) {
DEBUG_AI("Big problem in execute_standing_order - no orders!")
sprintf (outbuf, "%s %s has no standing orders to execute - aborting",
UnitString[unit->type], unit->name);
DEBUG_AI(outbuf)
return;
}
switch (unit->orders->reserved) {
case C_ORDER_GOTO:
result = AI1_command_headto(unit);
if (result < 0) clear_orders(unit); /* problem */
if (result == 0) clear_orders(unit); /* done */
break;
case C_ORDER_RANDOM:
AI1_command_random(unit);
break;
default:
DEBUG_AI("Unknown command type found in execute_standing_order!")
break;
}
return;
}
void AI1_command_random( struct Unit* unit )
{
enum Direction Randdir = RangeRand(6L);
int i;
/* About as simple as it gets! We'll try 10 times to make a valid move.*/
for( i=0; i < 10; i++ ) {
if( move_unit_dir(unit, Randdir) != -1 ) return;
Randdir = RangeRand(6L);
}
return;
}
int AI1_command_headto( struct Unit* unit )
{
int i, j;
int result;
/* Check to see if we have arrived */
if ((unit->col == unit->orders->destx) &&
(unit->row == unit->orders->desty)) {
/* We have arrived! */
/* DEBUG_AI("We have arrived!") */
return (0);
}
/* Select the correct direction to look in */
i = 0;
if (unit->orders->destx - unit->col <= 0) i = 3;
if( (unit->orders->destx == unit->col) && (unit->col%2 == 0) ) i = 0;
if (unit->orders->desty - unit->row < 0) i += 1;
if (unit->orders->desty == unit->row) i += 2;
/* Let's move in the three most likely directions only */
for (j = 0; j < 3; j++) {
/* -1 is the only return value where a move might still be possible
We must be sure we only do ONE move - ever */
if ((result = move_unit_dir(unit, DirArray[i][j])) != -1) {
/*sprintf (outbuf, "Moved %s, result %ld",
DirString[DirArray[i][j]], result);
DEBUG_AI(outbuf)
*/
if( (result > -3) && (unit->orders) ) {
/* We didn't die in an attack, and we didn't crash, so
let's check for destination again
*/
/*DEBUG_AI("Checking for Destination") */
if ((unit->col == unit->orders->destx) &&
(unit->row == unit->orders->desty)) {
/* We have arrived! */
/* DEBUG_AI("We have arrived!") */
return (0);
}
unit->orders->etc--;
if (unit->orders->etc < 0) {
DEBUG_AI("Watchdog on HeadTo ran out")
return (-2);
}
}
return (1);
}
else {
sprintf (outbuf, "%s %s Tried to move in direction %s, result %ld",
UnitString[unit->type], unit->name, DirString[DirArray[i][j]],
result);
DEBUG_AI(outbuf)
}
} /* End for loop */
/* No luck at all */
DEBUG_AI ("Cannot move towards - clearing orders")
return (-1);
}